package sbc.group1.lab1.alt;

import java.rmi.RemoteException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sbc.group1.lab1.common.Producer;

abstract class AbstractProducer implements Runnable, Producer {
    
    public static final int PRODUCTION_DURATION_MIN_MS = 1000;
    public static final int PRODUCTION_DURATION_MAX_MS = 3000;
    private static final Logger log = LoggerFactory.getLogger(AbstractProducer.class);
    
    private final int id;
    private int partsToProduce;
    private volatile boolean running = true;
    private double relativeDefects;
    
    private CarService cs = null;
    
    public AbstractProducer(int id, int partsToProduce, CarService cs, double relativeDefects) {
        this.id = id;
        this.partsToProduce = partsToProduce;
        this.cs = cs;
        this.relativeDefects=relativeDefects;
    }
    
    @Override
    public void run() {
        while(isRunning()) {
            try {
                synchronized (this) {
                    wait(getProductionDurationMs());
                }
            	createAndAddPart(cs);
                partsToProduce--;
                log.info("Part successfully produced.");
            } catch (RemoteException e1) {
                log.error("Part production failed!",e1);
            } catch (InterruptedException e) {
                halt();
                log.info("Interrupted! Stopping...");
                return;
            }
        }
    }
    
    protected abstract void createAndAddPart(CarService cs) throws RemoteException, InterruptedException;
    
    private boolean isRunning() {
        return partsToProduce > 0 && running;
    }
    
    public void halt() {
        running = false;
    }
    
    public int getId() {
        return id;
    }
    
    private int getProductionDurationMs() {
        return PRODUCTION_DURATION_MIN_MS + (int)(Math.random() *
                (PRODUCTION_DURATION_MAX_MS-PRODUCTION_DURATION_MIN_MS));
    }
    
    public final boolean randomIsDefect() {
        if (relativeDefects <= 0.0) {
            return false;
        }else if (relativeDefects >= 1.0) {
            return true;
        }else {
            return relativeDefects > Math.random();
        }
    }
    
}
   